#if !defined(SM__CONFIG_H)
#define SM__CONFIG_H

#include <string>
#include <map>
#include <vector>
#include <list>
#include <iostream>

/*

  ConfigDOM
  =========
  These two files (config.h and config.cpp) comprise a simple wrapper around the
  expat parser to provide DOM-like access to XML data.  The wrapper/library depends
  upon expat and standard C++ library elements:  vector, map, list, string.

  The library provides a VERY small subset of the DOM Level 2 Core specification
  (http://www.w3.org/TR/DOM-Level-2-Core/).  Some extensions to this API are
  provided for convenience.

  The library is not XML namespace-aware.

  At the moment, there is no way to modify the DOM structure (i.e. add, remove,
  move nodes).  You can only modify the attributes of existing nodes.  Future
  revisions of the library may provide traditional DOM methods for this:
  appendChild(), insertBefore(), replaceChild(), removeChild().  See the TODO
  list below.

  The library is released under the GPLv2.

  Version     Date        Notes
  =============================================================================
    0.1     2007-12-19    First annotated version with header.  Simple DOM-like
                          access to XML data from within C++.
  =============================================================================

  Jeff Schiller

*/

struct XMLNode;

typedef std::map<std::string,std::string> AttrMap;
typedef AttrMap::iterator AttrIter;
typedef AttrMap::const_iterator ConstAttrIter;

typedef std::vector<XMLNode*> NodeArray;
typedef NodeArray::iterator NodeArrayIter;

typedef std::list<XMLNode*> NodeList;
typedef NodeList::iterator NodeListIter;

// Global API
XMLNode* loadConfig(const char* szConfigFilename);
bool saveConfig(XMLNode* rootNode, const char* szConfigFilename);
void serializeXMLNode(std::ostream& os, XMLNode* node);

// This is a list of things that could be done.  It's possible that NONE of these
// things will be done though:
//
// TODO:  Add appendChild, insertBefore, replaceChild and removeChild methods
// TODO:  Provide member variables for firstChild, lastChild, previousSibling, nextSibling?
//        (Note: This makes all methods that change the DOM structure slower - worth it?)
// TODO:  Provide a convenience method for getting an attribute (maybe _("foo") ?)
//        and then remove the specific id() function?
// TODO:  Create an Attribute class that wraps up getting/setting and uses operator= ?
// TODO:  Create a NodeList class that wraps up a container of nodes and provides the item()
//        method and length property?
// TODO:  Become namespace-aware (and provide namespace-aware methods)
// TODO:  Preserve XML processing instructions...

// For the XML entity <sprite id="blah" />, we have an XMLNode where
// - tagName = "sprite"
// - attr["id"] = "blah"
struct XMLNode {
  std::string tagName;
  AttrMap attr;
  // this can be nodes XML elements or text nodes, use DOM methods below
  NodeList childNodes;
  XMLNode* parentNode;
  std::string textContent;

  XMLNode();
  // deletes the children nodes
  ~XMLNode();

  // needed?
  const std::string& id() const;

  // ======================================================================= //
  // DOM Methods
  // ======================================================================= //
  const std::string& getAttribute(const std::string& name) const;  // TODO: test this method
  void setAttribute(const std::string& name, const std::string& value); // TODO: test this method
  bool hasAttribute(const std::string& name) const;  // TODO: test this method
  void removeAttribute(const std::string& name);  // TODO: test this method  

  // finds the first element matching the input ID
  // returns NULL if no element found
  XMLNode* getElementById(const char* elemID);

  // returns the first element matching the tag name
  XMLNode* getElementByTagName(const char* _tagName);

  // if outArr is not NULL, this function appends all matching elements to outArr
  // returns the number of elements found of that tagname
  int getElementsByTagName(const char* _tagName, NodeArray* outArr);
  int getElementsByTagName(const char* _tagName, NodeList* outList);

  bool hasChildNodes() const;
  // ======================================================================= //
};

// helper macros
#define ATOI(inStr) atoi(inStr.c_str())
#define ATOF(inStr) atof(inStr.c_str())

#endif // SM__CONFIG_H
